"""
与登陆和注册相关的视图函数

"""
from datetime import datetime
import random
import re
from flask import request, session, current_app, jsonify
import logging
from info import redis_store, db
from info.models import User
from info.utils.captcha import captcha
from info.utils.response_code import RET
from . import passport_blu
from flask import make_response
from info.constants import IMAGE_CODE_REDIS_EXPIRES
from info.constants import SMS_CODE_REDIS_EXPIRES
from info.libs.CCPA import MSGHelp


# 完成退出登陆逻辑
@passport_blu.route("/logout", methods=["POST"])
def logout():
    """
    完成退出登陆逻辑
    :return:
    """
    # 接收到请求，完成退出登陆操作
    # 1 清除session信息
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)

    return jsonify(errno=RET.OK, errmsg="成功退出")


# 完成登陆逻辑
@passport_blu.route("/login", methods=["POST"])
def login():
    """
    完成登陆逻辑

    :param mobile: 用户输入的手机号码
    :param password: 用户输入的 密码
    :return: JSON{errno:XXXX,errmsg:YYYY} 根据json数据内容，前端可以获知用户是否位合法用户
    """
    # 1 获取用户输入的内容
    login_params = request.json

    mobile = login_params["mobile"]
    pwd = login_params["password"]

    # 2 检验数据是否为空
    if not all([mobile, pwd]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 3 校验用户输入的内容和数据的内容进行匹配
    # 3.1 校验用户是否存在
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.debug(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库查询错误")
    if not user:
        # 找不到该用户
        return jsonify(errno=RET.USERERR, errmsg="用户不存在")
    # 3.2 校验密码输入是否正确
    if not user.check_passowrd(pwd):
        return jsonify(errno=RET.PWDERR, errmsg="密码输入错误")

    # 4 保存登陆信息（如果用户存在，且输入的密码正确，那么就保留当前用户的登陆信息）
    session["user_id"] = user.id
    session["nick_name"] = user.nick_name
    session["mobile"] = user.mobile

    # 4.1   记录用户最后一次登录时间
    user.last_login = datetime.now()
    try:
        db.session.commit()  # 直接更新数据
    except Exception as e:
        current_app.logger.debug(e)

    # 5 返回结果
    return jsonify(errno=RET.OK, errmsg="登陆成功")


@passport_blu.route("/reg", methods=["POST"])
def reg():
    # 完成注册的逻辑
    # 接收来自浏览器提交的数据 注册逻辑的参数reg_params
    reg_params = request.json

    mobile = reg_params["mobile"]
    smscode = reg_params["smscode"]
    pwd = reg_params["pwd"]

    # 1 传递来的参数是否都有
    if not all([mobile, smscode, pwd]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    # 2 判断验证码是否填写正确
    # 2.1 从redis数据库中获取验证码信息
    try:
        local_active_code = redis_store.get("mobile_active_code:" + mobile).decode()
    except Exception as e:
        current_app.logger.debug(e)
        return jsonify(errno=RET.DBERR, errmsg="获取本地验证码失败")
    if not local_active_code:
        return jsonify(errno=RET.NODATA, errmsg="手机激活码过期")

    # 2.2 判断本地的验证码是否跟用户输入的一致
    if local_active_code != smscode:
        return jsonify(errno=RET.DATAERR, errmsg="手机激活码输入错误")

    # 2.3 如果用户输入的验证码和本地匹配，那么删除本地的验证码信息
    try:
        redis_store.delete("mobile_active_code:" + mobile)
    except Exception as e:
        current_app.logger.debug(e)

    # 3 把用户信息添加到数据库中
    # 判断该手机是否已经注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.debug(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库连接失败")
    if user:
        return jsonify(errno=RET.USERERR, errmsg="该手机号码已被注册")

    user = User(nick_name=mobile, mobile=mobile)
    user.password = pwd  # 里面用了装饰器 会自动的调用里面的加密方法而且会自动的把user.password_hash添加进去

    # 把用户添加进数据库
    db.session.add(user)
    db.session.commit()
    # 提交成功之后，记得要返回对应的参数  连接数据库，打开文件都要用try
    # 注册成功后，要给浏览器保存状态。这个状态既保存在redis数据库中，也会跟随cookies保存在用户电脑上
    session["user_id"] = user.id
    session["nick_name"] = user.nick_name
    session["mobile"] = user.mobile

    return jsonify(errno=RET.OK, errmsg="注册成功")


# 因为前面写了前缀，所以这个访问不了
# http://127.0.0.1:5000/passport/passport/image_code?code_id=51d84734-f15f-44ea-81c0-828577cb9c79S
# 参数是code_id
# ImmutableMultiDict([('code_id', '51d84734-f15f-44ea-81c0-828577cb9c79')]) <class 'werkzeug.datastructures.ImmutableMultiDict'>
# <function image_code at 0x0000014077865EA0>  这个request.args是一个方法。只不过是被property属性装饰了的
# @passport_blu.route("/image_code")  # 因为前面加了前缀，所以不用在前面添加passport当请求中含有/passport
# 开头的请求，会自动找这个
@passport_blu.route("/image_code")
def image_code():
    # 获得用户GET发来的请求的参数(随机数)
    # print(request.args,type(request.args))
    code_id = request.args["code_id"]
    # 判断code_id 不存在的情况
    if not code_id:
        return jsonify(errno=RET.PARAMERR, errmsg="验证码随机参数错误")

    # 根据code_id 随机产生一个图片  图片的产生 captcha模块实现
    # 调用captcha.generate_captcha()
    name, text, image = captcha.captcha.generate_captcha()

    # print(name, text)

    # 生成的信息存储到redis数据库
    try:
        # 保存code_id 和 text 信息，并且设置时间为300秒
        redis_store.setex("code_id:" + code_id, IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        current_app.logger.error(e)  # 如果出错，把错误信息保存
        # 返回提示信息
        return make_response(jsonify(errno=RET.DATAERR, errmsg='保存图片验证码失败'))

    # 把图片返回出去
    # print(image)
    # print(type(image))
    # 下面是设置响应头的方式，因为image是一个字节流。
    image = make_response(image)
    image.headers['Content-Type'] = 'image/jpg'

    return image


# 发送短信验证码逻辑
@passport_blu.route("/sms_code", methods=["POST"])
def sms_code():
    """发送短信到用户注册的手机号码上"""
    # 获取浏览器通过json发送来的数据
    param_dic = request.json
    mobile = param_dic["mobile"]
    image_code = param_dic["image_Code"]
    image_code_id = param_dic["image_Code_Id"]

    """
    需要对参数进行如下判断：
    1 参数是否完全
    2 手机号码是否合法
    3 手机号码是否被注册
    4 用户输入的验证码信息是否和redis数据库中的匹配  
    """

    # 当用户输入的验证码信息OK且手机号码在数据库中不存在，那么就OK
    if not all([mobile, image_code, image_code_id]):
        # 返回一个json格式的数据  里面是关键字参数
        return jsonify(errno=RET.PARAMERR, errmsg="缺少参数")

    # 判断手机号码是否合法
    if not re.match(r"^1[3-9]\d{9}$", mobile):
        # 返回一个json格式的内容
        return jsonify(errno=RET.DATAERR, errmsg="手机号不正确")

    # 检验用户输入的验证码信息是否跟保存在redis数据库中的一致
    # 先从redis数据库中根据用户的随机ID来查询验证码的值
    # 3. 通过传入的图片编码去redis中查询真实的图片验证码内容
    try:
        resulet_code = redis_store.get("code_id:" + image_code_id).decode()
        # 如果能取出来，删除redis中的缓存内容
        if resulet_code:
            redis_store.delete("code_id:" + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取图片验证码失败")

    # 判断验证码是否过期（验证码是否还保留在reids数据库中)
    if not resulet_code:
        return jsonify(errno=RET.NODATA, errmsg="验证码过期")

    # 判断用户输入的验证码信息是否和图片内容一致
    if resulet_code.upper() != image_code.upper():
        return jsonify(errno=RET.DATAERR, errmsg="验证码输入错误")

    # 校验手机号码是否被注册
    # 从数据库中根据手机号码查询结果
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库查询错误")
    if user:
        # 该手机对应的用户已经存在
        return jsonify(errno=RET.USERERR, errmsg="该手机已被注册")

    # 上述验证都通过了，就开始发送短信
    # 1 设置短信验证码内容
    temp_code = random.randint(0, 999999)  # 产生一个6位数的验证码信息
    mobile_active_code = "%06d" % temp_code  # 把信息补全6位
    # 保存调试信息
    current_app.logger.debug("短信验证码的内容：" + mobile_active_code)
    # 发送短信验证码到指定手机上
    result_send = MSGHelp().sendTemplateSMS(mobile, [mobile_active_code, 5], 1)
    if result_send != 0:
        return jsonify(errno=RET.THIRDERR, errmsg="发送短信失败")
    # 把产生的短信激活码信息写入redis数据库中
    try:
        redis_store.setex("mobile_active_code:" + mobile, SMS_CODE_REDIS_EXPIRES, mobile_active_code)

    except Exception as e:
        current_app.logger.debug(e)
        return jsonify(errno=RET.DBERR, errmsg="保存短信验证码失败")

    # 短信发送成功，返回一个成功的响应信息
    return jsonify(errno=RET.OK, errmsg="短信发送成功")
